Scrapbox UserScriptからSocket.IOを使
code:script.js
export function importSocketIO(version = "4.2.0") {
const url = https://cdnjs.cloudflare.com/ajax/libs/socket.io/${version}/socket.io.min.js;
if (document.querySelector(script[src="${url}"])) {
return Promise.resolve().then(() => globalThis.io);
}
const script = document.createElement("script");
script.src = url;
return new Promise((resolve, reject) => {
script.onload = () => resolve(globalThis.io);
script.onerror = (e) => reject(e);
document.head.append(script);
});
}
テスト
code:test.js
const io = await importSocketIO("4.2.0");
cf.
code:test.js
const socket = io(location.origin, {reconnectionDelay: 5000, transports: "websocket"}); minifyしたコードサイズはcdnjs版の2倍くらいある
?bundleを付けないとさらに数倍に膨れ上がってしまうので注意
特定のprojectに接続する
code:test2.js
const io = await importSocketIO("4.2.0");
const socket = io(location.origin, {reconnectionDelay: 5000, transports: "websocket"}); const result = await new Promise(res => socket.emit("socket.io-request",{
method: "room:join",
data: {
pageId: null,
projectId: "5f2f02f3c4a48d00237e1534",
projectUpdatesStream: false,
},
}, (e) => res(e)));
console.info(result);
socket.disconnect();
特定のprojectのstreamを購読する
https://gyazo.com/6033e5b170502f1d6c05adf290e26680
code:stream.js
const project = "villagepump";
const PROJECT_ID = "5e2455255664e000177a46fc";
const io = await importSocketIO("4.2.0");
const socket = io(location.origin, {reconnectionDelay: 5000, transports: "websocket"}); const result = await new Promise(res => socket.emit("socket.io-request",{
method: "room:join",
data: {
pageId: null,
projectId: PROJECT_ID,
projectUpdatesStream: true,
},
}, (e) => res(e)));
console.info("Start subscribing stream");
左下に表示する
code:stream.js
const div = document.createElement("div");
const shadowRoot = div.attachShadow({mode: "open"});
shadowRoot.innerHTML = `
<style>
:host {
position: fixed;
left: 0;
bottom: 0;
z-index: 9999;
text-decoration: none;
background-color: var(--page-bg);
color: var(--page-text-color);
border: solid 1px var(--telomere-unread);
border-radius: 4px;
padding: 8px;
margin: 10px;
}
button {
display: inline-block;
}
</style>
<div>
<button id="button">x</button>
<span id="title">caption</span>
</div>
<table>
<thead>
<tr>
<th>type</th>
<th>id</th>
<th>lines</th>
</tr>
</thead>
<tbody id="table">
</tbody>
</table>
<pre><code id="code">
</code></pre>
`;
document.body.append(div);
socket.on("projectUpdatesStream:commit", (data) => {
const {parentId, changes, pageId, userId, projectId, id} = data;
const title = pageId;
const commitMsg = ${title}@${project}\n${parentId.slice(0, 8)} -> ${id.slice(0, 8)};
shadowRoot.getElementById("title").innerText = commitMsg;
shadowRoot.getElementById("table").textContent = "";
shadowRoot.getElementById("table").append(...changes.map(change => {
const {_update, _insert, _delete, lines} = change;
const tr = document.createElement("tr");
const type = document.createElement("td");
type.textContent = _update ? "~" :
_insert ? "+" :
_delete ? "-" : "unknown";
const commitId = document.createElement("td");
commitId.textContent = (_update ?? _insert ?? _delete ?? "unknown").slice(0, 8);
const linesTd = document.createElement("td");
linesTd.textContent = lines.text ?? lines.origText;
tr.append(type, commitId, linesTd);
return tr;
}));
});
閉じる
code:stream.js
shadowRoot.getElementById("button").onclick = () => {
console.info("End subscribing stream");
socket.disconnect();
div.remove();
};